/**
 *  @file DateTime.h
 */
#ifndef _DATETIME_H_
#define _DATETIME_H_

#include "../common/BaseObject.h"
#include "DateTimeEnum.h"
#include "TimeDuration.h"

namespace cppflib
{

namespace util
{

/**
 *  Represents datetime using Gregorian calendar
 */
class _DLLAPI DateTime : public BaseObject
{

public:
    typedef enum _datetimekind
    {
       DTK_UTC,         ///< it is a UTC time
       DTK_LOCAL        ///< it is a local time
    } datetimekind_t;

private:
    i64_t ticks;    ///< one unit is 100 nanosecond or 10^-7 sec or 0.0000001 sec
    datetimekind_t dtKind;

    DateTime(void);
    void ReleaseBeforeThrowing();

    void InitDateTime(int year, int month, int day, int hour, int min, int sec, int milliSec, datetimekind_t dtKind);
    void ShiftOneMonth(bool isShiftForward, int dayOfMonth);
public:
    DateTime(const DateTime& dt);
    const DateTime& operator=(const DateTime& dt);

    explicit DateTime(i64_t ticks);
    DateTime(i64_t ticks, datetimekind_t dtKind);
    DateTime(int year, int month, int day);
    DateTime(int year, int month, int day, datetimekind_t dtKind);
    DateTime(int year, int month, int day, int hour, int min, int sec);
    DateTime(int year, int month, int day, int hour, int min, int sec, datetimekind_t dtKind);
    DateTime(int year, int month, int day, int hour, int min, int sec, int milliSec);
    DateTime(int year, int month, int day, int hour, int min, int sec, int milliSec, datetimekind_t dtKind);
    virtual ~DateTime(void);

    int Year() const;
    int Month() const;
    int Day() const;
    int Hour() const;
    int Min() const;
    int Sec() const;
    int MilliSec() const;
    i64_t Ticks() const; 
    datetimekind_t Kind() const;
    bool IsLeapYear() const;

    DateTime& Add(const TimeDuration &td);
    DateTime& AddYears(int years);
    DateTime& AddMonths(int months);
    DateTime& AddDays(int days);
    DateTime& AddHours(int hours);
    DateTime& AddMinutes(i64_t mins);
    DateTime& AddSeconds(i64_t seconds);
    DateTime& AddMilliSeconds(i64_t milliSecs);
    DateTime& AddTicks(i64_t ticks);

    int Compare(const DateTime& dt) const;

    DateTime ToLocalTime() const;
    DateTime ToUtcTime() const;
    DateTime Date();
    TimeDuration TimeOfDay() const;
    cppflib::util::dayofweek_t DayOfWeek();
    int DayOfYear() const;

    /************************
     *  from BaseObject
     ************************/
    virtual bool Equals(const BaseObject &obj) const;
    virtual u32_t GetHash(void) const;
    virtual pcwstr_t ToString(void) const;

public:
    PUBLIC bool IsLeapYear(int year);
    PUBLIC int DaysInMonth(int year, int month);
    PUBLIC cppflib::util::dayofweek_t DayOfWeek(int year, int month, int day);
    PUBLIC DateTime * Now();
    PUBLIC DateTime * UtcNow();
    PUBLIC DateTime * Today();
    PUBLIC DateTime NowValue();
    PUBLIC DateTime UtcNowValue();
    PUBLIC DateTime MinDateTime();
    PUBLIC DateTime MaxDateTime();
    PUBLIC DateTime GetDateTimeFromEpoch(i64_t epochTime);
    PUBLIC i64_t GetEpochFromDateTime(const DateTime& dt);
};

_DLLAPI bool operator==(const DateTime& d1, const DateTime& d2);
_DLLAPI bool operator!=(const DateTime& d1, const DateTime& d2);
_DLLAPI bool operator<(const DateTime& d1, const DateTime& d2);
_DLLAPI bool operator>(const DateTime& d1, const DateTime& d2);
_DLLAPI bool operator<=(const DateTime& d1, const DateTime& d2);
_DLLAPI bool operator>=(const DateTime& d1, const DateTime& d2);
_DLLAPI DateTime operator+(const DateTime& dt, const TimeDuration& td);
_DLLAPI DateTime operator-(const DateTime& dt, const TimeDuration& td);
_DLLAPI TimeDuration operator-(const DateTime& d1, const DateTime& d2);


} // end of namespace util

} // end of namespace cppflib

#endif

